/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package lansupportclient;

import ObjectHandler.LanSupportMessage;
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

/**
 *
 * @author Cong
 */
public class ClientListener implements Runnable {
    
    private Socket listenSocket;
    private Socket sendSocket;
    private lansupportclient.LanSupportClient lanSupportClient;
    
    public ClientListener(Socket listenSocket, Socket sendSocket, lansupportclient.LanSupportClient lanSupportClient) {
        this.listenSocket = listenSocket;
        this.sendSocket = sendSocket;
        this.lanSupportClient = lanSupportClient;
    }
    
    @Override
    public void run() {
        LanSupportMessage lanSupportMessage = new LanSupportMessage();
        byte[] xx = new byte[8], yy = new byte[8];
        long x, y, keycode;
        MouseController controller = null;
        KeyboardController keyboardController = null;
        ShellCmd shellCmd = new ShellCmd(sendSocket);
        try {
            controller = new MouseController();
            keyboardController = new KeyboardController();
        } catch (AWTException ex) {
            Logger.getLogger(ClientListener.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            boolean _continue = true;
            SendScreen sendScreenViewScreen = null;
            SendScreen sendScreenForRemote = null;
            while (_continue) {
                
                lanSupportMessage.Receive(listenSocket);
                String type = lanSupportMessage.getType();
                System.out.println(type);
                byte[] data = lanSupportMessage.getData();
                
                switch (type) {
                    case LanSupportMessage.CheckConnection:
                        break;
                    
                    case LanSupportMessage.ChatMessageType:
                        String chatMessage = new String(data);
                        lanSupportClient.AddMessage(chatMessage);
                        break;
                    
                    case LanSupportMessage.ServerToClientMessageType:
                        String serverMessage = new String(data);
                        lanSupportClient.ShowMessageFromServer(serverMessage);
                        break;
                    
                    case LanSupportMessage.FileType:
                        lanSupportClient.SaveFile(data);
                        break;
                    
                    case LanSupportMessage.ClientScreenshotType:
                        byte[] image = CaptueScreen();
                        lanSupportClient.SendScreenHot(image);
                        break;
                    
                    case LanSupportMessage.StartViewScreen:
                        sendScreenViewScreen = new SendScreen(sendSocket);
                        Thread threadViewScreen = new Thread(sendScreenViewScreen);
                        threadViewScreen.start();
                        break;
                    case LanSupportMessage.StopViewScreen:
                        sendScreenViewScreen.setContinue(false);
                        break;
                    
                    case LanSupportMessage.CloseConnection:
                        _continue = false;
                        break;
                    
                    case LanSupportMessage.StartRemoteDesktop:
                        Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
                        LanSupportMessage message = new LanSupportMessage(LanSupportMessage.ClientScreenSize);
                        byte[] screen = new byte[16];
                        System.arraycopy(_long2Bytes(screenRect.width), 0, screen, 0, 8);
                        System.arraycopy(_long2Bytes(screenRect.height), 0, screen, 8, 8);
                        message.setData(screen);
                        message.Send(sendSocket);
                        sendScreenForRemote = new SendScreen(sendSocket, LanSupportMessage.ViewRemoteDesktop);
                        Thread threadRemoteDesktop = new Thread(sendScreenForRemote);
                        threadRemoteDesktop.start();
                        break;
                    
                    case LanSupportMessage.StopRemoteDesktop:
                        sendScreenForRemote.setContinue(false);
                        break;
                    
                    case LanSupportMessage.LeftMouseClick:
                        System.arraycopy(data, 0, xx, 0, 8);
                        System.arraycopy(data, 8, yy, 0, 8);
                        x = _bytes2Long(xx);
                        y = _bytes2Long(yy);
                        controller.Clicked(1, x, y);
                        break;
                    case LanSupportMessage.MouseRelease:
                        System.arraycopy(data, 0, xx, 0, 8);
                        System.arraycopy(data, 8, yy, 0, 8);
                        x = _bytes2Long(xx);
                        y = _bytes2Long(yy);
                        controller.Released(1, x, y);
                        break;
                    case LanSupportMessage.RightMouseClick:
                        System.arraycopy(data, 0, xx, 0, 8);
                        System.arraycopy(data, 8, yy, 0, 8);
                        x = _bytes2Long(xx);
                        y = _bytes2Long(yy);
                        controller.Clicked(3, x, y);
                        break;
                    case LanSupportMessage.RightMouseRelease:
                        System.arraycopy(data, 0, xx, 0, 8);
                        System.arraycopy(data, 8, yy, 0, 8);
                        x = _bytes2Long(xx);
                        y = _bytes2Long(yy);
                        controller.Released(3, x, y);
                        break;
                    case LanSupportMessage.WheelMouseClick:
                        System.arraycopy(data, 0, xx, 0, 8);
                        System.arraycopy(data, 8, yy, 0, 8);
                        x = _bytes2Long(xx);
                        y = _bytes2Long(yy);
                        controller.Clicked(2, x, y);
                        break;
                    case LanSupportMessage.WheelMouseRelease:
                        System.arraycopy(data, 0, xx, 0, 8);
                        System.arraycopy(data, 8, yy, 0, 8);
                        x = _bytes2Long(xx);
                        y = _bytes2Long(yy);
                        controller.Released(2, x, y);
                        break;
                    case LanSupportMessage.MouseMoved:
                        System.arraycopy(data, 0, xx, 0, 8);
                        System.arraycopy(data, 8, yy, 0, 8);
                        x = _bytes2Long(xx);
                        y = _bytes2Long(yy);
                        controller.Move(x, y);
                        break;
                    case LanSupportMessage.keyPress:
                        keycode = _bytes2Long(data);
                        keyboardController.KeyPress(keycode);
                        break;
                    case LanSupportMessage.keyRelease:
                        keycode = _bytes2Long(data);
                        keyboardController.KeyRelease(keycode);
                        break;
                    case LanSupportMessage.Shellcmd:
                        String cmd = new String(data);
                        shellCmd.Exec(cmd);
                        break;
                }
            }
            listenSocket.close();
        } catch (Exception e) {
        }
    }
    
    private byte[] CaptueScreen() {
        Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
        BufferedImage bufferedImage;
        byte[] imageInByte = null;
        Robot robot;
        try {
            robot = new Robot();
            bufferedImage = robot.createScreenCapture(screenRect);
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                ImageIO.write(bufferedImage, "png", baos);
                baos.flush();
                imageInByte = baos.toByteArray();
            }
        } catch (IOException | AWTException ex) {
            Logger.getLogger(ClientListener.class.getName()).log(Level.SEVERE, null, ex);
        }
        return imageInByte;
    }
    
    private long _bytes2Long(byte[] bs) {
        long value = 0;
        for (int i = 0; i < bs.length; i++) {
            byte c = bs[i];
            value = (value << 8) + (c & 0xff);
        }
        return value;
    }
    
    private byte[] _long2Bytes(long l) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(8);
        byteBuffer.putLong(l);
        byte[] byteResult = byteBuffer.array();
        return byteResult;
    }
}
